/*
 * @(#)XDSUtils.java
 * Date 2013-04-10
 * Version 1.0
 * DocumentEntryAuthor Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.registry.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.xml.bind.JAXBElement;

import oasis.names.tc.ebxml_regrep.xsd.lcm._3.SubmitObjectsRequest;

import oasis.names.tc.ebxml_regrep.xsd.rim._3.ClassificationType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ExtrinsicObjectType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.IdentifiableType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.InternationalStringType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.LocalizedStringType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ObjectFactory;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.RegistryPackageType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.SlotType1;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.ValueListType;
import oasis.names.tc.ebxml_regrep.xsd.rim._3.VersionInfoType;

import org.apache.commons.codec.digest.DigestUtils;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import org.joda.time.DateTime;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import us.hornerscorners.lamppost.model.common.CodedElement;

import us.hornerscorners.lamppost.model.document.DocumentEntry;
import us.hornerscorners.lamppost.model.document.Folder;
import us.hornerscorners.lamppost.model.document.SubmissionSet;

import us.hornerscorners.lamppost.registry.constant.AvailabilityStatus;
import us.hornerscorners.lamppost.registry.constant.Metadata;
import us.hornerscorners.lamppost.registry.constant.SlotName;

import us.hornerscorners.lamppost.utils.UTCDateUtils;
import us.hornerscorners.lamppost.utils.UUIDUtils;


/**
 *
 * @author jim
 */
public class XDSUtils {

    /** Field description */
    private static final Logger logger = LoggerFactory.getLogger(XDSUtils.class);

    /** Field description */
    public static final ObjectFactory RIMObjectFactory = new ObjectFactory();

    /**
     * Method description
     *
     *
     * @param id
     *
     * @return
     */
    public static String assignEntryUUID(String id) {

        String result = id;

        if (isSymbolicId(id)) {

            result = String.format("%s%s", UUIDUtils.URN_PREFIX,
                                   UUID.randomUUID().toString().toLowerCase());
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param value
     *
     * @return
     */
    public static String calculateHash(byte[] value) {

        return DigestUtils.sha1Hex(value);
    }

    /**
     * Method description
     *
     *
     * @param sor
     *
     * @return
     */
    public static Map<String, ExtrinsicObjectType> createDocumentEntryMap(
            SubmitObjectsRequest sor) {

        Map<String, ExtrinsicObjectType> result = new HashMap<>();

        String docentryuuid = Metadata.DocumentEntryClassificationNode.getURN();

        for (JAXBElement<? extends IdentifiableType> jaxbelem :
                sor.getRegistryObjectList().getIdentifiable()) {

            IdentifiableType idtype = jaxbelem.getValue();
            String key = idtype.getId();

            if (idtype instanceof ExtrinsicObjectType) {

                ExtrinsicObjectType eo = (ExtrinsicObjectType) idtype;

                String objType = eo.getObjectType();

                if (docentryuuid.equals(objType)) {

                    result.put(key, eo);
                }
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     *
     * @param eo
     * @param slotNames
     * @return
     */
    public static Map<SlotName, SlotType1> createSlotMap(ExtrinsicObjectType eo,
            SlotName... slotNames) {

        Map<SlotName, SlotType1> result = new HashMap<>();

        if (ArrayUtils.isNotEmpty(slotNames)) {

            for (SlotType1 slot : eo.getSlot()) {

                SlotName slotName = SlotName.toSlotName(slot.getName());

                if (ArrayUtils.contains(slotNames, slotName)) {

                    result.put(slotName, slot);
                }
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     *
     * @param sor
     * @return
     */
    public static RegistryPackageType findSubmissionSet(SubmitObjectsRequest sor) {

        RegistryPackageType result = null;

        for (JAXBElement<? extends IdentifiableType> jaxbelem :
                sor.getRegistryObjectList().getIdentifiable()) {

            IdentifiableType idtype = jaxbelem.getValue();

            if (idtype instanceof RegistryPackageType) {

                RegistryPackageType regpack = (RegistryPackageType) idtype;

                if (XDSUtils.isSubmissionSet(regpack)) {

                    result = regpack;

                    break;
                }
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param status
     *
     * @return
     */
    public static boolean isApproved(CodedElement status) {

        boolean result = false;

        if (status != null) {

            if (AvailabilityStatus.Approved.getCode().equals(status.getCode())) {

                result = true;
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param exobj
     *
     * @return
     */
    public static boolean isDocument(ExtrinsicObjectType exobj) {

        boolean result = false;

        String objType = exobj.getObjectType();

        if (Metadata.DocumentEntryClassificationNode.getURN().equals(objType)) {

            result = true;
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param regpack
     *
     * @return
     */
    public static boolean isFolder(RegistryPackageType regpack) {

        boolean result = false;

        String folderClassUUID = Metadata.FolderClassificationNode.getURN();

        for (ClassificationType ctype : regpack.getClassification()) {

            if (folderClassUUID.equals(ctype.getClassificationNode())) {

                result = true;

                break;
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param docentry
     * @param statusCode
     *
     * @return
     */
    public static boolean isInStatus(DocumentEntry docentry, String statusCode) {

        boolean result = false;

        CodedElement status = docentry.getAvailabilityStatus();

        if ((status != null) && StringUtils.equals(statusCode, status.getCode())) {

            result = true;
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param folder
     * @param statusCode
     *
     * @return
     */
    public static boolean isInStatus(Folder folder, String statusCode) {

        boolean result = false;

        CodedElement status = folder.getAvailabilityStatus();

        if ((status != null) && StringUtils.equals(statusCode, status.getCode())) {

            result = true;
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param subSet
     * @param statusCode
     *
     * @return
     */
    public static boolean isInStatus(SubmissionSet subSet, String statusCode) {

        boolean result = false;

        CodedElement status = subSet.getAvailabilityStatus();

        if ((status != null) && StringUtils.equals(statusCode, status.getCode())) {

            result = true;
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param status
     *
     * @return
     */
    public static boolean isNotApproved(CodedElement status) {

        return (isApproved(status) == false);
    }

    /**
     * Method description
     *
     *
     * @param sourceId
     *
     * @return
     */
    public static boolean isNotSymbolicId(String sourceId) {

        return (isSymbolicId(sourceId) == false);
    }

    /**
     * Method description
     *
     *
     * @param regpack
     *
     * @return
     */
    public static boolean isSubmissionSet(RegistryPackageType regpack) {

        boolean result = false;

        String subsetClassUUID = Metadata.SubmissionSetClassificationNode.getURN();

        for (ClassificationType ctype : regpack.getClassification()) {

            if (subsetClassUUID.equals(ctype.getClassificationNode())) {

                result = true;

                break;
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param id
     *
     * @return
     */
    public static boolean isSymbolicId(String id) {

        return UUIDUtils.isNotValidWithURN(id);
    }

    /**
     * Method description
     *
     *
     * @param slotName
     *
     * @return
     */
    public static boolean isValidExtraSlotName(String slotName) {

        boolean result = false;

        if (StringUtils.startsWith(slotName, "urn:")
                && (StringUtils.startsWith(slotName, "urn:ihe:") == false)) {
            result = true;
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param slot
     *
     * @return
     */
    public static DateTime parseDTM(SlotType1 slot) {

        DateTime result = null;

        String value = parseFirstValue(slot);

        if (StringUtils.isNotBlank(value)) {

            result = parseDTM(value);
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param dtm
     *
     * @return
     */
    public static DateTime parseDTM(String dtm) {

        return UTCDateUtils.parseDate(dtm, UTCDateUtils.DATE_TIME_FORMATS);
    }

    /**
     * Method description
     *
     *
     * @param slot
     *
     * @return
     */
    public static String parseFirstValue(SlotType1 slot) {

        String result = null;

        if (slot != null) {

            result = parseFirstValue(slot.getValueList());
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param vtype
     *
     * @return
     */
    public static String parseFirstValue(ValueListType vtype) {

        String result = null;

        if (vtype != null) {

            List<String> list = vtype.getValue();

            if ((list != null) && (list.isEmpty() == false)) {

                result = list.get(0);
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param value
     *
     * @return
     */
    public static String parseNameString(InternationalStringType value) {

        String result = null;

        if (value != null) {

            for (LocalizedStringType ltype : value.getLocalizedString()) {

                // TODO should look at lang/charset??
                if (result == null) {

                    result = ltype.getValue();

                    break;
                }
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param slot
     *
     * @return
     */
    public static List<String> parseValues(SlotType1 slot) {

        List<String> result = new ArrayList<>();

        if (slot != null) {

            ValueListType valueType = slot.getValueList();

            if (valueType != null) {

                result.addAll(valueType.getValue());
            }
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param version
     *
     * @return
     */
    public static String parseVersionName(VersionInfoType version) {

        String result = null;

        if (version != null) {

            result = version.getVersionName();
        }

        return result;
    }
}
